package com.zmn.oms.business.impl.eventsnotice;

import com.alibaba.fastjson.JSON;
import com.zmn.common.constant.GlobalConsts;
import com.zmn.common.utils.collection.CollectionUtil;
import com.zmn.common.utils.date.DateUtil;
import com.zmn.common.utils.number.NumberUtil;
import com.zmn.manager.mq.interfaces.ZmnMQSender;
import com.zmn.oms.business.interfaces.eventsnotice.EventsNoticeBService;
import com.zmn.oms.business.interfaces.productcoderefund.ProductCodeRefundBService;
import com.zmn.oms.common.constant.*;
import com.zmn.oms.common.dto.OmsBaseOperator;
import com.zmn.oms.common.dto.OmsOperator;
import com.zmn.oms.common.dto.QueueOrderNodeNotifyDTO;
import com.zmn.oms.constant.MessageQueueTopicConstant;
import com.zmn.oms.model.dto.order.OrderDTO;
import com.zmn.oms.model.dto.work.masterwork.ModifyDutyTimeDTO;
import com.zmn.oms.model.dto.work.modify.OrderMultipleVisitDTO;
import com.zmn.oms.model.entity.changerecord.OrderChangeRecord;
import com.zmn.oms.model.entity.detail.OrderDetail;
import com.zmn.oms.model.entity.discount.OrderDiscount;
import com.zmn.oms.model.entity.log.OrderLog;
import com.zmn.oms.model.entity.order.OrderExtend;
import com.zmn.oms.model.entity.work.OrderWork;
import com.zmn.oms.services.interfaces.changerecord.OrderChangeRecordService;
import com.zmn.oms.services.interfaces.detail.OrderDetailService;
import com.zmn.oms.services.interfaces.discount.OrderDiscountService;
import com.zmn.oms.services.interfaces.work.OrderWorkService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 类描述：事件通知
 *
 * @author heciqi
 * @date 2021/10/19 11:30
 */
@Slf4j
@Service
public class EventsNoticeBServiceImpl implements EventsNoticeBService {
    @Autowired
    OrderWorkService orderWorkService;
    @Autowired
    OrderDetailService orderDetailService;
    @Autowired
    OrderDiscountService orderDiscountService;
    @Autowired
    OrderChangeRecordService orderChangeRecordService;

    @Resource
    private ProductCodeRefundBService productCodeRefundBService;

    @Resource
    ZmnMQSender zmnMQSender;

    /**
     * oms 事件通知
     *
     * @param orderLog
     * @param dbOrderWork
     * @param newOrderWork
     * @param dbOrderExtend
     * @param omsBaseOperator
     * @param proceed
     * @return
     */
    @Override
    public void notice(OrderLog orderLog, OrderWork dbOrderWork, OrderWork newOrderWork, OrderExtend dbOrderExtend, OmsBaseOperator omsBaseOperator, Object proceed) {
        final Integer logType = orderLog.getType();
        log.info("EventsNoticeBServiceImpl.notice OrderWork:{},logType:{}", dbOrderWork, logType);
        OrderWork orderWork = null;
        OrderDetail orderDetail = null;

        {// 准备有效的 orderWork 和 orderDetail
            boolean isSync = OmsEventsConsts.SYNC_ORDER_NODE_MAP.containsKey(logType);
            if (!isSync) {
                return;// 不处理无需同步的操作
            }
            log.debug("nodeNotice2-orderLog.getType=>{}，omsBaseOperator==>{}", logType, omsBaseOperator);
            if (Objects.equals(OrderLogConsts.ORDER_LOG_TYPE_INPUT, logType)) {
                orderWork = newOrderWork;
            } else if (omsBaseOperator instanceof OmsOperator) {
                OmsOperator omsOperator = (OmsOperator) omsBaseOperator;
                if (omsOperator.getOrderId() != null && omsOperator.getWorkId() != null) {
                    orderWork = orderWorkService.findOrderWorkByKeySrcMaster(
                            omsOperator.getOrderId(), omsOperator.getWorkId()
                    );
                }

            }
            if (orderWork == null) {
                return;
            }
            if (dbOrderWork == null) {
                dbOrderWork = orderWork;
            }
            // 初始化变量：orderDetail
            orderDetail = orderDetailService.findOrderDetailByKeySrcMaster(orderWork.getOrderId());
            if (orderDetail == null) {
                return;
            }
        }

        // 待发送消息容器
        final Map<String, QueueOrderNodeNotifyDTO> msgPairs = new HashMap<>(3);

        // 订单修改操作
        if (Objects.equals(OrderLogConsts.ORDER_LOG_TYPE_UPDATE, logType)) {
            OrderDTO orderDTO = (OrderDTO) omsBaseOperator;
            OrderDetail dbOrderDetail = orderDTO.getDbOrderDetail();
            OrderDetail newOrderDetail = orderDTO.getOrderDetail();
            {// 修改，手机号码变更新
                // 手机号码变更
                String updateBeforePhone = StringUtils.defaultString(dbOrderDetail.getTelephone());
                String newTelephone = StringUtils.defaultString(newOrderDetail.getTelephone());
                String updateBeforePhone2 = StringUtils.defaultString(dbOrderDetail.getTelephone2());
                String newTelephone2 = StringUtils.defaultString(newOrderDetail.getTelephone2());
                if (!StringUtils.equals(newTelephone, updateBeforePhone)
                        || !StringUtils.equals(newTelephone2, updateBeforePhone2)) {
                    log.info("手机号码dbTelephone[{}],[{}]改成telephone[{}]，[{}]发送队列",
                            updateBeforePhone, newTelephone, updateBeforePhone2, newTelephone2
                    );

                    QueueOrderNodeNotifyDTO notifyDTO = this._generateQueueOrderNodeNotifyDTO4NodeNotice2(
                            orderWork, orderDetail, dbOrderExtend, orderLog
                    );
                    notifyDTO.setUpdateBeforePhone(updateBeforePhone);
                    notifyDTO.setUpdateBeforePhone2(updateBeforePhone2);

                    msgPairs.put(PublishTagConsts.PUBLISH_ORDER_UPDATE_PHONE, notifyDTO);
                }
            }
            {// 预约时间: 修改操作中修改预约时间
                Date newDutyTime = orderWork.getDutyTime();
                if (newDutyTime != null && DateUtil
                        .toTimestampMillis(dbOrderWork.getDutyTime()) != DateUtil.toTimestampMillis(newDutyTime)) {
                    QueueOrderNodeNotifyDTO notifyDTO = this._generateQueueOrderNodeNotifyDTO4NodeNotice2(
                            orderWork, orderDetail, dbOrderExtend, orderLog
                    );
                    notifyDTO.setDutyTime(newDutyTime.getTime());
                    msgPairs.put(PublishTagConsts.PUBLISH_ORDER_UPDATE_DUTYTIME, notifyDTO);
                }
            }

            {   // 地址修改
                if (!Objects.equals(dbOrderDetail.getLatitude(), newOrderDetail.getLatitude()) || !Objects
                        .equals(dbOrderDetail.getLongitude(), newOrderDetail.getLongitude())) {
                    QueueOrderNodeNotifyDTO notifyDTO = this._generateQueueOrderNodeNotifyDTO4NodeNotice2(
                            orderWork, orderDetail, dbOrderExtend, orderLog
                    );
                    msgPairs.put(PublishTagConsts.PUBLISH_ORDER_UPDATE_ADDRESS, notifyDTO);
                }
            }
            {
                // 产品修改
                if (orderDTO.getOrderWork() != null) {
                    if (!Objects.equals(dbOrderWork.getShowProductId(), orderDTO.getOrderWork().getShowProductId())) {
                        QueueOrderNodeNotifyDTO notifyDTO = this._generateQueueOrderNodeNotifyDTO4NodeNotice2(
                                orderWork, orderDetail, dbOrderExtend, orderLog);
                        msgPairs.put(PublishTagConsts.PUBLISH_ORDER_UPDATE_PRODUCT, notifyDTO);
                    }
                }
            }

            // 挂起
            if (Objects.equals(OrderDutyConsts.DUTY_STATUS_FAIL, orderWork.getDutyStatus())
                    && orderWork.getNextContactTime() != null) {
                QueueOrderNodeNotifyDTO notifyDTO = this._generateQueueOrderNodeNotifyDTO4NodeNotice2(
                        orderWork, orderDetail, dbOrderExtend, orderLog
                );
                notifyDTO.setDutyStatus(OrderDutyConsts.DUTY_STATUS_FAIL);
                notifyDTO.setNextContactTime(orderWork.getNextContactTime().getTime());
                notifyDTO.setReasonCode(Objects.isNull(orderWork.getDutyFailCode())
                        ? GlobalConsts.NONE
                        : orderWork.getDutyFailCode()
                );
                msgPairs.put(PublishTagConsts.PUBLISH_ORDER_SUSPEND, notifyDTO);
            }

            // 修改
            QueueOrderNodeNotifyDTO updateNotifyDTO = this._generateQueueOrderNodeNotifyDTO4NodeNotice2(
                    orderWork, orderDetail, dbOrderExtend, orderLog);
            msgPairs.put(PublishTagConsts.PUBLISH_ORDER_UPDATE, updateNotifyDTO);
        }
        // 师傅修改产品
        else if (Objects.equals(PublishTagConsts.PUBLISH_ORDER_UPDATE_PRODUCT, logType)) {
            QueueOrderNodeNotifyDTO updateNotifyDTO = this._generateQueueOrderNodeNotifyDTO4NodeNotice2(
                    orderWork, orderDetail, dbOrderExtend, orderLog);
            msgPairs.put(PublishTagConsts.PUBLISH_ORDER_UPDATE_PRODUCT, updateNotifyDTO);
        }
        // 师傅修改预约时间
        else if (Objects.equals(OrderLogConsts.ORDER_LOG_TYPE_MASTER_MODIFY_DUTY_TIME, logType)
                && omsBaseOperator instanceof ModifyDutyTimeDTO) {
            ModifyDutyTimeDTO modifyDutyTimeDTO = (ModifyDutyTimeDTO) omsBaseOperator;
            Date dutyTime = modifyDutyTimeDTO.getDutyTime();
            if (dutyTime != null) {
                QueueOrderNodeNotifyDTO notifyDTO = this._generateQueueOrderNodeNotifyDTO4NodeNotice2(
                        orderWork, orderDetail, dbOrderExtend, orderLog
                );
                notifyDTO.setDutyTime(dutyTime.getTime());
                msgPairs.put(PublishTagConsts.PUBLISH_ORDER_UPDATE_DUTYTIME, notifyDTO);
            }
        } else if (Objects.equals(OrderLogConsts.ORDER_LOG_TYPE_REFUND_RESULT, logType)) {
            // 品码对接退款
            productCodeRefundBService.sendProductCodeRefundMsg(orderWork, logType);
        }
        // 其他操作
        else {
            QueueOrderNodeNotifyDTO notifyDTO = this._generateQueueOrderNodeNotifyDTO4NodeNotice2(
                    orderWork, orderDetail, dbOrderExtend, orderLog
            );

            // 完成时，优惠不为空则携带优惠列表
            if (Objects.equals(OrderLogConsts.ORDER_LOG_TYPE_COMPLETE, logType)
                    && NumberUtil.isNotNullOrZero(orderWork.getDiscountAmount())) {
                List<OrderDiscount> orderDiscountList = orderDiscountService.listByOrderId(orderWork.getOrderId());
                if (CollectionUtil.isNotNullOrEmpty(orderDiscountList)) {
                    notifyDTO.setItemCodes(orderDiscountList.stream()
                            .filter(e -> org.apache.commons.lang.StringUtils.isNotBlank(e.getItemCode()))
                            .map(e -> e.getItemCode())
                            .collect(Collectors.toList())
                    );
                }
            }
            // 工程师申请多次上门操作：需要获取下次上门时间
            else if (Objects.equals(OrderLogConsts.ORDER_LOG_TYPE_APPLY_MULTIPLE_VISIT, logType)) {
                if (omsBaseOperator instanceof OrderMultipleVisitDTO) {
                    notifyDTO.setDutyTime(
                            Optional.ofNullable(((OrderMultipleVisitDTO) omsBaseOperator).getExpectVisitTime())
                                    .map(Date::getTime)
                                    .orElse(null)
                    );
                }
            }
            msgPairs.put(OmsEventsConsts.SYNC_ORDER_NODE_MAP.get(logType), notifyDTO);
        }
        // 发送消息
        Iterator<Map.Entry<String, QueueOrderNodeNotifyDTO>> iterator = msgPairs.entrySet().iterator();
        while (iterator.hasNext()) {
            Map.Entry<String, QueueOrderNodeNotifyDTO> item = iterator.next();
            String tag = item.getKey();
            String msgContent = JSON.toJSONString(item.getValue());
            String msgKey = String.valueOf(orderWork.getWorkId());

            log.info("[{}]订单状态发布TAG[{}]-队列[{}]", msgKey, tag, msgContent);
            long time = System.currentTimeMillis() + 5000;// 延迟5秒发送
            zmnMQSender.sendWithStartDeliverTime(MessageQueueTopicConstant.ZMN_TOPIC_OMS, tag, msgKey, msgContent, time);
        }
    }

    /**
     * oms 事件通知
     *
     * @param orderId
     * @param workId
     * @param queueTag 队列tag
     */
    @Override
    public void notice(Long orderId, Long workId, String queueTag) {
        OrderWork orderWork = orderWorkService.findOrderWorkByKeySrcMaster(orderId, workId);
        if (Objects.isNull(orderWork)) {
            log.error("未找到工单[{}]", workId);
            return;
        }
        OrderDetail orderDetail = orderDetailService.findOrderDetailByKeySrcMaster(orderWork.getOrderId());

        QueueOrderNodeNotifyDTO queueOrderNodeNotifyDTO = this._generateQueueOrderNodeNotifyDTO4NodeNotice2(orderWork, orderDetail, null, null);
        String msgContent = JSON.toJSONString(queueOrderNodeNotifyDTO);
        String msgKey = String.valueOf(workId);
        log.info("[{}]订单状态发布TAG[{}]-队列[{}]", msgKey, queueTag, msgContent);
        long time = System.currentTimeMillis() + 5000;// 延迟5秒发送
        zmnMQSender.sendWithStartDeliverTime(MessageQueueTopicConstant.ZMN_TOPIC_OMS, queueTag, msgKey, msgContent, time);
    }

    /**
     * oms 事件通知
     *
     * @param orderWork
     * @param orderDetail
     * @param queueTag    队列tag
     */
    @Override
    public void notice(OrderWork orderWork, OrderDetail orderDetail, String queueTag) {
        if (Objects.isNull(orderWork)) {
            return;
        }

        QueueOrderNodeNotifyDTO queueOrderNodeNotifyDTO = this._generateQueueOrderNodeNotifyDTO4NodeNotice2(orderWork, orderDetail, null, null);
        String msgContent = JSON.toJSONString(queueOrderNodeNotifyDTO);
        String msgKey = String.valueOf(orderWork.getWorkId());
        log.info("[{}]订单状态发布TAG[{}]-队列[{}]", msgKey, queueTag, msgContent);
        long time = System.currentTimeMillis() + 5000;// 延迟5秒发送
        zmnMQSender.sendWithStartDeliverTime(MessageQueueTopicConstant.ZMN_TOPIC_OMS, queueTag, msgKey, msgContent, time);
    }

    /**
     * 生成节点通知消息DTO
     *
     * @param orderWork
     * @param orderDetail
     * @param dbOrderExtend
     * @return
     */
    private QueueOrderNodeNotifyDTO _generateQueueOrderNodeNotifyDTO4NodeNotice2(OrderWork orderWork,
                                                                                 OrderDetail orderDetail,
                                                                                 OrderExtend dbOrderExtend,
                                                                                 OrderLog orderLog) {
        QueueOrderNodeNotifyDTO build = QueueOrderNodeNotifyDTO.builder()
                .orderId(orderWork.getOrderId())
                .workId(orderWork.getWorkId())
                .receiveEntranceId(orderWork.getReceiveEntranceId())
                .type(orderWork.getType())
                .plat(orderWork.getPlat())
                .platWork(orderWork.getPlatWork())
                .status(orderWork.getStatus())
                .resultStatus(orderWork.getResultStatus())
                .channelId(orderWork.getChannelId())
                .phone(StringUtils.defaultString(orderDetail.getTelephone()))
                .updateBeforePhone("")
                .phone2(StringUtils.defaultString(orderDetail.getTelephone2()))
                .updateBeforePhone2("")
                .userId(orderWork.getUserId())
                .manageCompanyId(orderWork.getManageCompanyId())
                .companyId(orderWork.getCompanyId())
                .provinceId(orderDetail.getProvinceId())
                .cityId(orderWork.getCityId())
                .streetId(orderDetail.getStreetId())
                .streetSource(orderDetail.getStreetSource())
                .productGroupId(orderWork.getServProductGroupId())
                .productGroupName(orderWork.getServProductGroupName())
                .productInfo(orderDetail.getProductInfo())
                .masterId(orderWork.getMasterId())
                .masterName(orderWork.getMasterName())
                .servCategId(orderWork.getServCategId())
                .servCategName(orderDetail.getServCategName())
                .test(orderWork.getTest())
                .duplicate(orderWork.getDuplicate())
                .bizType(orderWork.getBizType())
                .servItemType(orderWork.getServItemType())
                .receiveTime(orderWork.getReceiveTime().getTime())
                .latitude(orderDetail.getLatitude())
                .longitude(orderDetail.getLongitude())
                .sendTime(DateUtil.getNow())
                .provinceName(orderDetail.getProvinceName())
                .cityName(orderDetail.getCityName())
                .countyName(orderDetail.getCountyName())
                .street(orderDetail.getStreet())
                .address(StringUtils.defaultString(orderDetail.getAddress(), ""))
                .build();
        // 完整地址
        build.setFullAddress(new StringBuilder()
                .append(orderDetail.getProvinceName()).append(orderDetail.getCityName())
                .append(orderDetail.getCountyName()).append(orderDetail.getStreet())
                .append(StringUtils.defaultString(orderDetail.getAddress(), ""))
                .toString()
        );

        // 预约时间
        if (Objects.nonNull(orderWork.getDutyTime())) {
            build.setDutyTime(orderWork.getDutyTime().getTime());
        }

        // clueId
        Optional.ofNullable(dbOrderExtend)
                .map(OrderExtend::getClueId)
                .ifPresent(clueId -> build.setClueId(clueId));

        // 操作人
        if (Objects.nonNull(orderLog)) {
            build.setOperatorId(orderLog.getOperatorId());
            build.setOperatorType(orderLog.getOperatorType());
            build.setOperator(orderLog.getOperator());
        }

        // 下单呼叫ID
        if (Objects.nonNull(dbOrderExtend) && Objects.equals(build.getType(), OrderConsts.ORDER_TYPE_NEW)) {
            build.setReceiveCallId(dbOrderExtend.getCallId());
        }

        // 取责任工程师
        if (NumberUtil.isNotNullOrZero(orderWork.getMasterId())) {
            OrderChangeRecord orderChangeRecord = orderChangeRecordService.getChangeRecordByOrderId(orderWork.getOrderId());
            if (Objects.nonNull(orderChangeRecord)) {
                build.setCancelLiableMasterId(orderChangeRecord.getCancelLiableMasterId());
                build.setCancelLiableMasterName(orderChangeRecord.getCancelLiableMasterName());
            }
        }
        return build;
    }
}
